use std::net::{Ipv4Addr, SocketAddrV4};
use std::str::FromStr;
use std::sync::OnceLock;
use clap::Parser;

pub const DEFAULT_LISTEN_PORT: u16 = 15053;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PeerEndpoint {
    Host(String),
    Addr(SocketAddrV4),
}

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct Settings {
    #[arg(long)]
    pub token: u32,
    #[arg(long = "vip")]
    pub virtual_ip: Ipv4Addr,
    #[arg(long = "peer")]
    pub peer_endpoints: Vec<PeerEndpoint>,
}

impl Settings {
    pub fn instance() -> &'static Self {
        static ME: OnceLock<Settings> = OnceLock::new();
        ME.get_or_init(|| Self::parse())
    }
}

impl FromStr for PeerEndpoint {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(ip) = s.parse::<Ipv4Addr>() {
            return Ok(Self::Addr(SocketAddrV4::new(ip, DEFAULT_LISTEN_PORT)));
        }
        if let Ok(addr) = s.parse::<SocketAddrV4>() {
            return Ok(Self::Addr(addr));
        }
        Ok(Self::Host(s.to_string()))
    }
}
